#include "soc.h"
#include <stdio.h>
#include <stdlib.h>
#include "delay.h"
#include "drv_timer.h"
#include "systemdata.h"
#include "ocv_table.h"
#include "soc.h"
#include "drv_rtc.h"

#define OCV_COMPUTE_TIME		60*60   	//  1h 静态校准

static Timer_t *soc_timer = NULL;
static SysConfData_t *confinfo = NULL;//系统参数指针
static SysRunData_t  *runinfo = NULL;//系统运行数据指针
static uint64_t fristOcvNum=0;
static uint64_t OcvNum=0;

//浮充阶段，判断满充。一共3个条件
//(1)电流不为0且小于0.05C；
//(2)单体最低电压必须达到电量为100%时的开路电压；
//(3)在满足1和2的前提下，计时达到1分钟.
static inline void floatFullCharge(void){//浮充阶段满充的判断
	static uint16_t fullchgtimer = 0;
	if(runinfo->batCur > 0 && runinfo->batCur < confinfo->fctData.normalCap.value*5){//电流为正且充电倍率小于0.05C
		if(runinfo->batMinVol >= socToOcv(100)){//单体最低电压必须达到ocv100时的单体电压
			fullchgtimer ++;
		}else{
			fullchgtimer = 0;
		}
	}else{
		fullchgtimer = 0;
	}
	if(fullchgtimer >= 600){//计时1分钟(60秒)
		fullchgtimer = 0;
		runinfo->fullChgFlag = true;
	}
}

static inline void cycleTimesUpdate(int64_t deltaAh){
	static int64_t cycleCap = 0;
	if(deltaAh > 0){//充电状态
		if(cycleCap < runinfo->norCap_mAmS){
			cycleCap += deltaAh;
		}else{//累计充电容量达到电池当前实际容量，更新循环次数
			cycleCap = 0;
			confinfo->fctData.cycleTimes.value ++;
			saveSysConfData();
		}
	}
}

//满充容量计算：从满放（fullDsgFlag为真）开始，中间没有经过放电，一直到满充(fullChgFlag为true)时充入的容量
static inline void fullChgCationtUpdate(int64_t deltaAh){
	if(deltaAh > 0){//充电状态
		if(runinfo->rmCapEmptyFlag == true){//如果是从过放开始充电，则计算充电容量，便于满充时计算电池实际容量
			if(runinfo->chgCap_mAmS >= runinfo->norCap_mAmS){
				runinfo->chgCap_mAmS = runinfo->norCap_mAmS;
			}else{
				runinfo->chgCap_mAmS += deltaAh;
			}
		}else{
			runinfo->chgCap_mAmS = 0;
		}
	}else{
		runinfo->chgCap_mAmS = 0;//如果连续充电过程被放电所打断，则满充容量归零
		runinfo->rmCapEmptyFlag = false;
	}
}

static inline void soc_integral_update(uint16_t time_ms){
	int64_t rmCap_mAmS = runinfo->rmCap_mAms;
	int64_t deltaAh = time_ms*runinfo->batCur;
	rmCap_mAmS += deltaAh;	
	if(rmCap_mAmS < 0){//防止越界
		rmCap_mAmS = 0;
	}else if(rmCap_mAmS > runinfo->realCap_mAms){//防止越界
		rmCap_mAmS = runinfo->realCap_mAms;
	}
	runinfo->rmCap_mAms = rmCap_mAmS;//更新剩余容量
	if(runinfo->realCap_mAms > 0){
		runinfo->batSoc = runinfo->rmCap_mAms*100/runinfo->realCap_mAms;
	}else{
		runinfo->batSoc = 0;
	}
	cycleTimesUpdate(deltaAh);//在充电情况下，判断循环次数是否需要更新
	fullChgCationtUpdate(deltaAh);//计算满充容量
	floatFullCharge();//浮充阶段满充判断
}

static inline void soc_ocv_update(uint16_t delta_time){
	static bool Ocvflag=0;
	if(abs(runinfo->batCur) < confinfo->fctData.wakeupCurrent.value){
		if(runinfo->volProtByte.cellHgVolProt == 0 && runinfo->volProtByte.cellLowVolProt == 0){
			if(Ocvflag == false){
				Ocvflag = true;
				fristOcvNum = batVolDiff_num();
//				printf("fristOcvNum=%lld\n",fristOcvNum);
			}
			OcvNum = batVolDiff_num();
			if ((OcvNum-fristOcvNum) >= OCV_COMPUTE_TIME){
				Ocvflag = false;
				updateOcvSoc();//未充放电计时达到，静态校准
//				printf("OcvNum=%lld\n",OcvNum);
//				printf("update OcvSoc\n");
			}
		}else{
			Ocvflag = false;
		}
	}else{
		Ocvflag = false;
	}
}
  

//soc满充校准以及电池实际容量自学习
//校准策略：
//1、如果单体过充，SOC置100
//2、如果充电电流小于0.05C(相对于电池标称容量而言)且持续超过5分钟，认为是满充
//3、满充时，如果rmCapEmptyFlag为true，即是从过放直接充到满充，将充电容量
static inline void soc_endian_calibration(void){
	if(runinfo->fullChgFlag == true && runinfo->volProtByte.cellLowVolProt == 0){//如果满充标志为真。增加单体未欠压的判断，是为了防止单体过压和单体欠压同时出现导致的误判
		runinfo->fullChgFlag = false;
		if(runinfo->rmCapEmptyFlag == true && runinfo->batSoc != 0){     		 //防止测试过程中操作异常导致实际容量更新为0
//			printf("update real caption\n");
			runinfo->realCap_mAms = runinfo->chgCap_mAmS;//更新实际容量
			confinfo->fctData.realCap.value = runinfo->realCap_mAms/1000/1000/360;
//			printf("runinfo->realCap_mAms = %lld\n",runinfo->realCap_mAms);
			saveSysConfData();
			runinfo->chgCap_mAmS = 0;
			runinfo->rmCapEmptyFlag = false;
			runinfo->batSoh = runinfo->realCap_mAms/10/1000/3600/confinfo->fctData.normalCap.value;
		}
		runinfo->rmCap_mAms = runinfo->realCap_mAms;
		runinfo->batSoc = 100;//soc置100
	}
	if(runinfo->fullDsgFlag == true){//满放啦
		runinfo->fullDsgFlag = false;
		runinfo->rmCap_mAms = 0;
		runinfo->batSoc = 0;
	}
}

static inline void soc_update(uint16_t delta_time){
	if(abs(runinfo->batCur) > confinfo->fctData.wakeupCurrent.value){
		soc_integral_update(delta_time);//安时积分
	}
	soc_ocv_update(delta_time);//静态校准
	soc_endian_calibration();//末端校准
}

static void soc_timer_callback(void *data){
	uint16_t time_1ms = *(uint16_t *)data;
	soc_update(time_1ms);
}

void soc_init(void){
	confinfo = getSysConfData();
	runinfo = getSysRunData();
	ocv_soc_init();
	runinfo->norCap_mAmS = ((uint64_t)confinfo->fctData.normalCap.value)*360*1000*1000;//实际容量初始化
	runinfo->realCap_mAms = ((uint64_t)confinfo->fctData.realCap.value)*360*1000*1000;//实际容量初始化
	runinfo->batSoh = runinfo->realCap_mAms*100/runinfo->norCap_mAmS;
	soc_timer = timer_create(soc_timer_callback,100);
	timer_start(soc_timer);
}